home *** CD-ROM | disk | FTP | other *** search
- /*
- File: FinderDragPro.c
-
- Description: Sample file illustrating drag and drop techniques for use
- with file system objects. This file illustrates how applications
- can use drag and drop commands in a way compatible with current
- and past versions of the Finder.
-
- This file is organized into the following sections:
-
- COPYING FILES
- routines used for copying files. For promised file flavors, we copy
- files to the destination directory. routines in this section manage
- file copy operations performed when providing promised files.
- SENDING DRAGS
- routines used for dragging files out of the main window. This includes
- code for both standard hfs flavors and promised hfs flavors.
- RECEIVING DRAGS
- routines for receiving drags dropped into the main window. this implementation
- only accepts drags containing one item that can be either a promised hfs flavor
- or a standard hfs flavor. Of interest here is code for handling promised hfs flavors
- provided by Find File.
- THE MAIN FINDER DRAG PRO WINDOW
- routines for maintaining the main window. These routines are responsible for
- drawing the window's contents, and for handling clicks in the main window.
- MENU HANDLING
- routines for processing menu commands. In this implementation, there are
- only two valid menu commands: one to quit the application and one to clear
- the main window's display.
- APPLE EVENT HANDLERS
- apple event handlers used in the application. Of interest here is the bogus Finder
- event handler installed for compatibility with past versions of the Finder.
- EVENT HANDLING
- general event processing routines used in the application including calls to
- WaitNextEvent and dispatching based on the event returned.
- MAIN
- the main routine including initialization code, the main loop, and termination code.
-
- Author: John Montbriand
- Some techniques borrowed from Pete Gontier's original FinderDragPro.
-
-
- Copyright: Copyright: © 1999 by Apple Computer, Inc.
- all rights reserved.
-
- Disclaimer: You may incorporate this sample code into your applications without
- restriction, though the sample code has been provided "AS IS" and the
- responsibility for its operation is 100% yours. However, what you are
- not permitted to do is to redistribute the source as "DSC Sample Code"
- after having made changes. If you're going to re-distribute the source,
- we require that you make it clear in the source that the code was
- descended from Apple Sample Code, but that you've made changes.
-
- Change History (most recent first):
- 9/9/99 by John Montbriand
- */
-
- #include "FinderDragPro.h"
- #include "GetIconSuiteFromFinder.h"
- #include "FDPUtilities.h"
-
- #include <Fonts.h>
- #include <Dialogs.h>
- #include <Icons.h>
- #include <PLStringFuncs.h>
- #include <TextUtils.h>
- #include <Gestalt.h>
- #include <QDOffscreen.h>
- #include <Sound.h>
- #include <StdIO.h>
- #include <String.h>
- #include <StdArg.h>
- #include <Devices.h>
- #include <Folders.h>
- #include <Appearance.h>
- #include <Threads.h>
-
-
- #ifndef __MWERKS__
- QDGlobals qd; /* QuickDraw globals */
- #endif
-
- /* application's globals */
- Boolean gRunning = true; /* true while the application is running, set to false to quit */
- Boolean gAppleEvents = false; /* true if the Apple event Manager is installed */
- Boolean gHasDragManager = false; /* true if the Drag Manager is installed */
- Boolean gCanTranslucentDrag = false; /* true if translucent dragging is available */
- Boolean gHasIconServices = false; /* true if icon services is available */
- Boolean gAppearance = false; /* true if the Appearance Manager is installed */
- Boolean gColorExists = false; /* true if Color QuickDraw is installed */
- Boolean gForground = true; /* true while FDP is the frontmost application */
- Boolean gHasThreads = true; /* true if the thread manager is defined */
- AEIdleUPP gAEIdleProc = NULL; /* idle proc called from AEInteractWithUser */
-
- /* globals specific to the main window */
- DialogPtr gDialog = NULL; /* a pointer to the main dialog */
- Rect gIconBox; /* area in the window where the information about the current file is drawn */
- Rect gIconImage; /* area inside of gIconBox where the icon is drawn */
- ControlHandle gPromiseControl; /* control for setting gDragMode to kUsePromiseHFS */
- ControlHandle gRegularControl; /* control for setting gDragMode to kUseRegularHFS */
- short gDragMode = kUseRegularHFS; /* determines the type of data we will provide for drags */
- PicHandle gSplashPict; /* splash image displayed in gIconBox when there is no file selected */
- UserItemUPP gFDPUserItemProc = NULL; /* UPP for the icon's user item. This routine draws into gIconBox */
- DragReceiveHandlerUPP gMainReceiveHandler = NULL; /* receive handler for the main dialog */
- DragTrackingHandlerUPP gMainTrackingHandler = NULL; /* tracking handler for the main dialog */
- DragSendDataUPP gSendDataProc = NULL; /* send data proc for the main dialog -- only used for promise hfs flavors. */
-
- /* file related variables */
- Boolean gFileInDisplay = false; /* true when gFileAlias contains an alias handle */
- AliasHandle gFileAlias; /* an alias to the last file dragged into the gIconBox */
- Boolean gFileUpToDate = false; /* true if we have an icon for the file */
- Handle gIconSuite; /* icon suite for displaying the file -- only used if gHasIconServices is false */
- IconRef gIconRef; /* an icon services reference to an icon for the file -- only used if gHasIconServices is true */
-
- /* gTargetFile refers to the last known location of the file referred to by gFileAlias. once
- every 2 seconds or so this location is compared to the location actually referred to by
- gFileAlias. If they differ, both gTargetFile and the display are updated. */
- FSSpec gTargetFile; /* refers to the last known location of the file. */
- OSType gType, gCreator; /* file type and creator for the file in the display */
- unsigned short gFlags; /* flags for the file in the display */
-
-
-
-
- /* COPYING FILES ------------------------------------------------ */
-
- /* for promise hfs flavors, FDP returns a fsspec referring to the file
- and then it completes the copy operation later after the drag and drop
- command has been completed. Most of the routines in this section are callbacks
- called by the CopyFileCmd routine defined in FDPUtilities.h. Normally, your
- application would create a new file containing interesting data rather than
- copying an existing one, but for the purposes of this example this is all
- we do here. */
-
- /* copy command variables */
- DialogPtr gCopyProgressWindow = NULL;
-
- /* HitCopyAsWindow is called when DialogSelect indicates an item has been
- hit in the copy progress window (gCopyProgressWindow). The only item
- we're interested in here is the 'Cancel' button. */
- static void HitCopyAsWindow(DialogPtr theDialog, EventRecord *ev, short itemNo) {
- if (itemNo == kCProCancelItem)
- AbortCopyOperation();
- }
-
- /* CopyProgressProc is called periodically during the file copy. It's main function
- is to swap out our task and allow other operating system services to run; however,
- if the copy operation takes longer than kCopyProgressTicksOffset and the copy operation
- is less than 90% complete it will pull up the copy progress window showing the status
- of the copy. */
- static void CopyProgressProc(FSSpec *theFile, short message, long percentCompleted) {
- static long gPercentDrawn = 0;
- static unsigned long gCopyStart = 0;
- switch (message) {
-
- case kCopyStart:
- gPercentDrawn = 0;
- gCopyProgressWindow = NULL;
- gCopyStart = TickCount();
- break;
-
- case kCopyRun:
- /* check the status of the copy status window */
- if (gCopyProgressWindow == NULL) {
- unsigned long now;
- /* has the copy been active longer than kCopyProgressTicksOffset
- and the command is less than 90 % complete. */
- now = TickCount();
- if ((now - gCopyStart > kCopyProgressTicksOffset) && (percentCompleted < 90)) {
- Point wLocation = {25, 25};
- /* display our progress window. Locate it relative to the main window. */
- ParamText(theFile->name, NULL, NULL, NULL);
- gCopyProgressWindow = GetNewDialog((gAppearance ? kCopyProgressDialog : kPlainCopyProgressDialog), NULL, (WindowPtr) (-1));
- SetPort(gDialog);
- LocalToGlobal(&wLocation);
- MoveWindow(gCopyProgressWindow, wLocation.h, wLocation.v, true);
- ShowWindow(gCopyProgressWindow);
- DrawDialog(gCopyProgressWindow); /* draw it */
- gPercentDrawn = 0;
- }
- } else if (gPercentDrawn != percentCompleted) {
- short itemt;
- Handle itemh;
- Rect itemb;
- GetDialogItem(gCopyProgressWindow, kCProIndicatorItem, &itemt, &itemh, &itemb);
- if (gAppearance) {
- SetControlValue((ControlHandle) itemh, percentCompleted);
- } else {
- Str255 textbuf;
- textbuf[0] = sprintf((char*) textbuf+1, "%d%% Complete", percentCompleted);
- SetDialogItemText(itemh, textbuf);
- }
- gPercentDrawn = percentCompleted;
- }
- break;
-
- case kCopyEnd:
- if (gCopyProgressWindow != NULL) DisposeDialog(gCopyProgressWindow);
- break;
-
- }
- }
-
- static void MyCopyErrorHandler(FSSpec *theFile, short errorCode) {
- if (errorCode == kCannotCopyDirError)
- ParamAlert(kCannotCopyDirAlert, theFile->name, NULL);
- else if (errorCode != userCanceledErr) {
- Str255 errNum;
- NumToString(errorCode, errNum);
- ParamAlert(kCopyFailedAlert, theFile->name, errNum);
- }
- }
-
-
-
-
-
- /* SENDING DRAGS ------------------------------------------------ */
-
-
-
- /* MyDragSendDataProc is the send data procedure used for providing promised
- flavors. In this routine we begin the copy operation to create the promised
- file by calling StartCopyCommand and return a FSSpec to the caller referring
- to the new file. */
- static pascal OSErr MyDragSendDataProc(FlavorType flavorType, void *refcon, ItemReference itemRef, DragReference dragRef) {
- OSErr err = noErr;
- AEDesc dropLocDesc, targetDirDesc;
- FSSpec theTarget, theSource, destinationDir;
- long destinationDirID;
- Str255 targetName;
- CInfoPBRec cat;
- Boolean wasChanged;
- FInfo srcInfo, dstInfo;
- Boolean destCreated;
-
- /* set up locals */
- AECreateDesc(typeNull, NULL, 0, NULL);
- AECreateDesc(typeNull, NULL, 0, NULL);
- destCreated = false;
-
- /* get the drop location where */
- err = GetDropLocation(dragRef, &dropLocDesc);
- if (err != noErr) goto bail;
-
- /* attempt to convert the location record to a FSSpec. By doing it this way
- instead of looking at the descriptorType field, we don't need to know what
- type the location originally was or what coercion handlers are installed. */
- err = AECoerceDesc(&dropLocDesc, typeFSS, &targetDirDesc);
- if (err != noErr) goto bail;
- BlockMoveData(*targetDirDesc.dataHandle, &destinationDir, sizeof(FSSpec));
-
- /* establish the target directory */
- cat.hFileInfo.ioNamePtr = destinationDir.name;
- cat.hFileInfo.ioVRefNum = destinationDir.vRefNum;
- cat.hFileInfo.ioDirID = destinationDir.parID;
- cat.hFileInfo.ioFDirIndex = 0;
- err = PBGetCatInfoSync(&cat);
- if (err != noErr) goto bail;
- destinationDirID = cat.hFileInfo.ioDirID;
-
- /* construct the target FSSpec, verify the name is free... */
- err = GetAliasInfo(gFileAlias, asiAliasName, targetName);
- if (err != noErr) goto bail;
- err = FSMakeFSSpec(destinationDir.vRefNum, destinationDirID, targetName, &theTarget);
- if (err == noErr) { err = dupFNErr; goto bail; }
- if (err != fnfErr) goto bail;
-
- /* find the source file.. */
- err = ResolveAliasQuietly(NULL, gFileAlias, &theSource, &wasChanged);
- if (err != noErr) goto bail;
-
- /* get the source file's finder info */
- err = FSpGetFInfo(&theSource, &srcInfo);
- if (err != noErr) goto bail;
-
- /* create the destination file. Unless the promised file is created in
- the drag send proc, the Finder will not position the icon correctly. */
- err = FSpCreate(&theTarget, srcInfo.fdCreator, srcInfo.fdType, smSystemScript);
- if (err != noErr) goto bail;
- destCreated = true;
-
- /* set the destintation's flags */
- err = FSpGetFInfo(&theTarget, &dstInfo);
- if (err != noErr) goto bail;
- dstInfo.fdFlags = (srcInfo.fdFlags & (~kHasBeenInited));
- err = FSpSetFInfo(&theTarget, &dstInfo);
- if (err != noErr) goto bail;
-
- /* begin the copy command. Now that the file has been created, we defer the
- remainder of the copy operation until after the drag. CopyFileCmd copies the
- resource fork and the data fork from a background thread. */
- err = CopyFileCmd(&theSource, &theTarget, CopyProgressProc, MyCopyErrorHandler);
- if (err != noErr) goto bail;
-
- /* return a reference to the new file to the caller */
- err = SetDragItemFlavorData(dragRef, itemRef, flavorType, &theTarget, sizeof(theTarget), 0);
- if (err != noErr) goto bail;
-
- /* clean up and leave */
- AEDisposeDesc(&targetDirDesc);
- AEDisposeDesc(&dropLocDesc);
- return noErr;
-
- bail:
- if (destCreated) FSpDelete(&theTarget);
- AEDisposeDesc(&targetDirDesc);
- AEDisposeDesc(&dropLocDesc);
- return err;
- }
-
-
-
-
- /* DragOut performs a drag operation from the main window to
- somewhere else. if gDragMode is kUsePromiseHFS, then DragOut
- performs a drag using a promised hfs flavor that triggers a copy
- operation when successful. If translucent dragging is supported, then
- a translucent drag image of the file's icon is added to the drag. */
- static pascal OSErr DragOut(const EventRecord *event) {
- DragReference dragRef;
- Boolean dragRefExists;
- Boolean hasDragImage;
- GWorldPtr imageGWorld;
- RgnHandle maskRgn, dragRgn, insetRgn;
- Point offsetPt, globalOrigin;
- OSErr err;
- Rect imageRect;
- HFSFlavor theFlavor;
-
- /* set up locals */
- dragRefExists = false;
- hasDragImage = false;
- imageGWorld = NULL;
- maskRgn = NULL;
- dragRgn = NULL;
- insetRgn = NULL;
-
- /* create a new dragreference */
- err = NewDrag(&dragRef);
- if (err != noErr) goto bail;
- dragRefExists = true;
-
- /* convert the file alias to a HFSFlavor structure */
- err = MakeHFSFlavorFromAlias(gFileAlias, &theFlavor);
- if (err != noErr) goto bail;
-
- /* add our flavors to the drag */
- if (gDragMode == kUsePromiseHFS) { /* if the option key is down work in promises */
- PromiseHFSFlavor phfs;
-
- /* add a send data proc */
- err = SetDragSendProc(dragRef, gSendDataProc, NULL);
- if (err != noErr) goto bail;
-
- /* add the promise flavor first */
- phfs.fileType = theFlavor.fileType;
- phfs.fileCreator = theFlavor.fileCreator;
- phfs.fdFlags = theFlavor.fdFlags;
- phfs.promisedFlavor = kPromisedFlavor;
- err = AddDragItemFlavor(dragRef, kFDPDragItemID, flavorTypePromiseHFS, &phfs, sizeof(phfs), flavorNotSaved);
- if (err != noErr) goto bail;
- /* add the HFS flavor immediately after the promise */
- err = AddDragItemFlavor(dragRef, kFDPDragItemID, kPromisedFlavor, NULL, 0, flavorNotSaved);
- if (err != noErr) goto bail;
-
- } else if (gDragMode == kUseRegularHFS) {
- /* add a hfs flavor to the drag */
- err = AddDragItemFlavor(dragRef, kFDPDragItemID, flavorTypeHFS, &theFlavor, sizeof(HFSFlavor), flavorNotSaved);
- if (err != noErr) goto bail;
- } else {
- err = paramErr;
- goto bail;
- }
-
- /* add a translucent image, if appropriate */
- if (gCanTranslucentDrag) {
- err = IconsToMaskedPixMap(&gIconImage, gIconSuite, gIconRef, &imageGWorld, &maskRgn);
- if (err == noErr) {
- imageRect = gIconImage;
- OffsetRect(&imageRect, -imageRect.left, -imageRect.top);
- SetPt(&offsetPt, gIconImage.left, gIconImage.top);
- LocalToGlobal(&offsetPt);
- err = SetDragImage(dragRef, GetGWorldPixMap(imageGWorld), maskRgn, offsetPt, kDragStandardTranslucency);
- if (err != noErr) goto bail;
- }
- }
-
- /* calculate an outline-style drag region */
- if ((dragRgn = NewRgn()) == NULL) { err = memFullErr; goto bail; }
- if (gHasIconServices)
- err = IconRefToRgn(dragRgn, &gIconImage, kAlignNone, kIconServicesNormalUsageFlag, gIconRef);
- else err = IconSuiteToRgn(dragRgn, &gIconImage, kAlignNone, gIconSuite);
- if (err != noErr) goto bail;
- if ((insetRgn = NewRgn()) == NULL) { err = memFullErr; goto bail; }
- CopyRgn(dragRgn, insetRgn);
- InsetRgn(insetRgn, 1, 1);
- DiffRgn(dragRgn, insetRgn, dragRgn);
- SetPt(&globalOrigin, qd.thePort->portRect.left, qd.thePort->portRect.top);
- LocalToGlobal(&globalOrigin);
- OffsetRgn(dragRgn, globalOrigin.h, globalOrigin.v);
-
- /* perform the drag operation */
- err = TrackDrag(dragRef, event, dragRgn);
- if (err == userCanceledErr) err = noErr;
- if (err != noErr) goto bail;
-
- /* clean up and leave */
- if (imageGWorld != NULL) DisposeGWorld(imageGWorld);
- if (maskRgn != NULL) DisposeRgn(maskRgn);
- DisposeRgn(dragRgn);
- DisposeRgn(insetRgn);
- DisposeDrag(dragRef);
- return noErr;
-
- bail: /* error recovery */
- if (imageGWorld != NULL) DisposeGWorld(imageGWorld);
- if (maskRgn != NULL) DisposeRgn(maskRgn);
- if (dragRgn != NULL) DisposeRgn(dragRgn);
- if (insetRgn != NULL) DisposeRgn(insetRgn);
- if (dragRefExists) DisposeDrag(dragRef);
- return err;
- }
-
-
-
-
- /* RECEIVING DRAGS ------------------------------------------------ */
-
-
- /* ApproveDragReference is called by the drag tracking handler to determine
- if the contents of the drag can be handled by our receive handler.
-
- This routine checks to see if there is only one item in the drag
- and that item contains either one of two flavors: 'flavorTypeHFS'
- or 'flavorTypePromiseHFS'. If the option key was held down at
- the beginning of the drag, then this routine only checks for
- the 'flavorTypePromiseHFS' in the first drag item.
- We accept one item and one item only.
-
- Note that if a flavor can't be found, it's not really an
- error; it only means the flavor wasn't there and we should
- not accept the drag. Therefore, we translate 'badDragFlavorErr'
- into a 'false' value for '*approved'. */
- static pascal OSErr ApproveDragReference(DragReference theDragRef, Boolean *approved) {
-
- OSErr err;
- UInt16 itemCount;
- DragAttributes dragAttrs;
- FlavorFlags flavorFlags;
- ItemReference theItem;
-
- /* we cannot drag to our own window */
- if ((err = GetDragAttributes(theDragRef, &dragAttrs)) != noErr) goto bail;
- if ((dragAttrs & kDragInsideSenderWindow) != 0) { err = userCanceledErr; goto bail; }
-
- /* we only accept drags containing one item */
- if ((err = CountDragItems(theDragRef, &itemCount)) != noErr) goto bail;
- if (itemCount != 1) { err = paramErr; goto bail; }
-
- /* gather information about the drag & a reference to item one. */
- if ((err = GetDragItemReferenceNumber(theDragRef, 1, &theItem)) != noErr) goto bail;
-
- /* check for flavorTypeHFS */
- err = GetFlavorFlags(theDragRef, theItem, flavorTypeHFS, &flavorFlags);
- if (err == noErr) {
- *approved = true;
- return noErr;
- } else if (err != badDragFlavorErr)
- goto bail;
-
- /* check for flavorTypePromiseHFS */
- err = GetFlavorFlags(theDragRef, theItem, flavorTypePromiseHFS, &flavorFlags);
- if (err == noErr) {
- *approved = true;
- return noErr;
- } else if (err != badDragFlavorErr)
- goto bail;
-
- /* none of our flavors were found */
- *approved = false;
- return noErr;
- bail:
- /* an error occured, clean up. set result to false. */
- *approved = false;
- return err;
- }
-
-
- /* these routines are used both in the receive handler and inside of the
- tracking handler. The following variables are shared between MyDragTrackingHandler
- and MyDragReceiveHandler. */
- static Boolean gApprovedDrag = false; /* set to true if the drag is approved */
- static Boolean gInIconBox = false; /* set true if the drag is inside our drop box */
-
-
- /* MyDragTrackingHandler is called for tracking the mouse while a drag is passing over our
- window. if the drag is approved, then the drop box will be hilitied appropriately
- as the mouse passes over it. */
- static pascal OSErr MyDragTrackingHandler(DragTrackingMessage message, WindowPtr theWindow, void *refCon, DragReference theDragRef) {
- /* we're drawing into the image well if we hilite... */
- switch (message) {
-
- case kDragTrackingEnterWindow:
- { Point mouse;
- gApprovedDrag = false;
- if (theWindow == FrontWindow()) {
- if (ApproveDragReference(theDragRef, &gApprovedDrag) != noErr) break;
- if ( ! gApprovedDrag ) break;
- SetPort(theWindow);
- GetMouse(&mouse);
- if (PtInRect(mouse, &gIconBox)) { /* if we're in the box, hilite... */
- SetPort(theWindow);
- gInIconBox = (ShowDragHiliteBox(theDragRef, &gIconBox) == noErr);
- }
- }
- }
- break;
-
- case kDragTrackingInWindow:
- if (gApprovedDrag) {
- Point mouse;
- SetPort(theWindow);
- GetMouse(&mouse);
- if (PtInRect(mouse, &gIconBox)) {
- if ( ! gInIconBox) { /* if we're entering the box, hilite... */
- SetPort(theWindow);
- gInIconBox = (ShowDragHiliteBox(theDragRef, &gIconBox) == noErr);
- }
- } else if (gInIconBox) { /* if we're exiting the box, unhilite... */
- HideDragHilite(theDragRef);
- gInIconBox = false;
- }
- }
- break;
-
- case kDragTrackingLeaveWindow:
- if (gApprovedDrag && gInIconBox) {
- HideDragHilite(theDragRef);
- }
- gApprovedDrag = gInIconBox = false;
- break;
- }
- return noErr; // there's no point in confusing Drag Manager or its caller
- }
-
-
-
-
- /* SetDragAndDropDirectory sets the drop location for the drag reference
- to the indicated directory. This routine will be called from inside of the
- drag receive handler when a promised hfs flavor about to be received. The purpose
- of the call to SetDropLocation is to tell the sending application where to put the
- promised file or folder. This routine sets up parameters referring to the
- (vRefNum, dirID) directory and calls SetDropLocation. */
- static OSErr SetDragAndDropDirectory(DragReference theDragRef, short vRefNum, long dirID) {
- Str255 name;
- CInfoPBRec cat;
- FSSpec spec;
- AliasHandle theAlias;
- AEDesc theDropLocation;
- OSErr err;
- /* set up locals */
- theAlias = NULL;
- AECreateDesc(typeNull, NULL, 0, NULL);
- /* find out the folder's parent ID */
- cat.hFileInfo.ioNamePtr = name;
- cat.hFileInfo.ioVRefNum = vRefNum;
- cat.hFileInfo.ioDirID = dirID;
- cat.hFileInfo.ioFDirIndex = -1;
- err = PBGetCatInfoSync(&cat);
- if (err != noErr) goto bail;
- /* now convert it to a FSSpec record */
- err = FSMakeFSSpec(vRefNum, cat.dirInfo.ioDrParID, name, &spec);
- if (err != noErr) goto bail;
- /* convert the FSSpec to an alias */
- err = NewAlias(NULL, &spec, &theAlias);
- if (err != noErr) goto bail;
- /* and make it into a descriptor record */
- HLock((Handle) theAlias);
- err = AECreateDesc(typeAlias,*theAlias, GetHandleSize((Handle) theAlias), &theDropLocation);
- if (err != noErr) goto bail;
- /* set it as the drag's drop location */
- err = SetDropLocation(theDragRef, &theDropLocation);
- if (err != noErr) goto bail;
- /* we're done, clean up */
- AEDisposeDesc(&theDropLocation);
- DisposeHandle((Handle) theAlias);
- return noErr;
- bail:
- AEDisposeDesc(&theDropLocation);
- if (theAlias != NULL) DisposeHandle((Handle) theAlias);
- return err;
- }
-
-
-
-
- /* MyDragReceiveHandler is the receive handler for the main window. It is called
- when a file or folder (or a promised file or folder) is dropped into the drop
- box in the main window. Here, if the drag reference has been approved in the
- track drag call, we handle three different cases:
-
- 1. standard hfs flavors,
-
- 2. promised flavors provided by find file,
-
- 3. promised flavors provided by other applications.
-
- After receiving a file, the display is updated. Any promised files are
- placed on the desktop. */
- static pascal OSErr MyDragReceiveHandler(WindowPtr theWindow, void *refcon, DragReference theDragRef) {
-
- ItemReference theItem;
- HFSFlavor targetFile;
- PromiseHFSFlavor targetPromise;
- FSSpec targetSpec;
- Size theSize;
- OSErr err;
-
- /* validate the drag. Recall the receive handler will only be called after
- the tracking handler has received a kDragTrackingInWindow event. As a result,
- the gApprovedDrag and gInIconBox will be defined when we arrive here. Hence,
- there is no need to spend extra time validating the drag at this point. */
- if ( ! (gApprovedDrag && gInIconBox) ) { err = userCanceledErr; goto bail; }
-
- /* get the first item reference */
- if ((err = GetDragItemReferenceNumber(theDragRef, 1, &theItem)) != noErr) goto bail;
-
- /* try to get a HFSFlavor*/
- theSize = sizeof(HFSFlavor);
- err = GetFlavorData(theDragRef, theItem, flavorTypeHFS, &targetFile, &theSize, 0);
- if (err == noErr) {
- SetNewDisplay(&targetFile);
- return noErr;
- } else if (err != badDragFlavorErr) goto bail;
-
- /* try to get a promised HFSFlavor*/
- theSize = sizeof(PromiseHFSFlavor);
- err = GetFlavorData(theDragRef, theItem, flavorTypePromiseHFS, &targetPromise, &theSize, 0);
- if (err != noErr) goto bail;
-
- /* check for a drop from find file */
- if (targetPromise.promisedFlavor == kPromisedFlavorFindFile) {
-
- /* from find file, no need to set the file location... */
- theSize = sizeof(FSSpec);
- err = GetFlavorData(theDragRef, theItem, targetPromise.promisedFlavor, &targetSpec, &theSize, 0);
- if (err != noErr) goto bail;
-
- } else {
- short deskVol;
- long deskDir;
- /* we'll put promised files on the desktop */
- err = FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder, &deskVol, &deskDir);
- if (err != noErr) goto bail;
- /* set the drag destination to the desktop */
- err = SetDragAndDropDirectory(theDragRef, deskVol, deskDir);
- if (err != noErr) goto bail;
-
- /* get the promised file */
- theSize = sizeof(FSSpec);
- err = GetFlavorData(theDragRef, theItem, targetPromise.promisedFlavor, &targetSpec, &theSize, 0);
- if (err != noErr) goto bail;
-
- /* verify the promise structure, make sure it's valid. */
- err = ValidFSSpec(&targetSpec);
- if (err != noErr) goto bail;
- }
- /* display the located file*/
- SetNewDisplay(&targetFile);
- return noErr;
- bail:
- return err;
- }
-
-
-
-
- /* THE MAIN FINDER DRAG PRO WINDOW ------------------------------------------------ */
-
-
- /* SetNewDisplay is called to set the file or folder being displayed in the main window.
- Here, structures are deallocated and an alias is saved referring to the file.
- SetNewDisplay is called from the drag receive handler and since it is not
- safe to call "GetIconSuiteFromFinder()" from inside of the drag receive handler
- (it uses apple events), the flag gFileUpToDate is used to defer that operation
- until the next time ValidateFDPWindowDisplay. ValidateFDPWindowDisplay is
- called from the main loop. If targetFile is NULL, then the display is cleared. */
- void SetNewDisplay(HFSFlavor *targetFile) {
- /* remove the old file */
- if (gFileInDisplay) {
- DisposeHandle((Handle) gFileAlias);
- if (gFileUpToDate) {
- if (gHasIconServices)
- ReleaseIconRef(gIconRef);
- else DisposeIconSuite(gIconSuite, true);
- gFileUpToDate = false;
- }
- gFileInDisplay = false;
- }
- /* set the new file, if there is one */
- if (targetFile != NULL) {
- gType = targetFile->fileType;
- gCreator = targetFile->fileCreator;
- gFlags = targetFile->fdFlags;
- gTargetFile = targetFile->fileSpec;
- gFileInDisplay = (NewAliasMinimal(&gTargetFile, &gFileAlias) == noErr);
- }
- /* post an update for the window */
- SetPort(gDialog);
- InvalRect(&gIconBox);
- }
-
-
- /* ValidateFDPWindowDisplay is called from the main loop, before update events,
- and when the application is switching in. It works together with SetNewDisplay.
- SetNewDisplay is called from the drag receive handler where sometimes it is
- unsafe to retrieve a file's icons. Instead of gathering the icon information inside
- of SetNewDisplay, SetNewDisplay sets the flag gFileUpToDate. ValidateFDPWindowDisplay
- watches gFileUpToDate. When this flag is false and there is a new file to be displayed,
- ValidateFDPWindowDisplay retrieves the icon and posts an update event for the window.
- To minimize resolve alias calls, if the icons have been fetched, then the alias is only
- verified at most once per second. */
- static OSErr ValidateFDPWindowDisplay(void) {
- Boolean wasChanged;
- OSErr err;
- static unsigned long gLastValidCall = 0;
- unsigned long now;
-
- wasChanged = false;
-
- if (gFileInDisplay) {
- now = TickCount();
- if ( ( ! gFileUpToDate) || (gLastValidCall == 0) || (now - gLastValidCall >= 60)) {
- gLastValidCall = now;
- err = ResolveAliasQuietly(NULL, gFileAlias, &gTargetFile, &wasChanged);
- if (err != noErr) goto bail;
- if ( ! gFileUpToDate) {
- if (gHasIconServices) {
- SInt16 theLabel;
- err = GetIconRefFromFile(&gTargetFile, &gIconRef, &theLabel);
- } else err = GetIconSuiteFromFinder(&gTargetFile, &gIconSuite);
- if (err != noErr) goto bail;
- gFileUpToDate = true;
- wasChanged = true;
- }
- }
- }
- if (wasChanged) {
- SetPort(gDialog);
- InvalRect(&gIconBox);
- }
- return noErr;
- bail:
- SetNewDisplay(NULL);
- return err;
- }
-
-
-
- /* MyFDPUserItem draws the image in the drop box in the window. If the window
- is not the active window, then the image is drawn grayed out. If appearance
- is in use, then the drop box is drawn as a generic well. */
- static pascal void MyFDPUserItem(WindowPtr theWindow, DialogItemIndex itemNo) {
- Rect rdraw;
- RGBColor sForground, sBackground;
- RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF}, rgbBlack = {0, 0, 0}, rgbGray = {0x7FFF, 0x7FFF, 0x7FFF};
- /* set up */
- SetPort(theWindow);
- /* set the colors we're using for drawing */
- if (gColorExists) {
- GetForeColor(&sForground);
- GetBackColor(&sBackground);
- RGBForeColor(&rgbBlack);
- RGBBackColor(&rgbWhite);
- }
- /* draw the frame */
- if (gAppearance) {
- ThemeDrawState themeDrawState;
- themeDrawState = (gForground && (theWindow == FrontWindow())) ? kThemeStateActive : kThemeStateInactive;
- DrawThemeGenericWell(&gIconBox, themeDrawState, true);
-
- } else {
- rdraw = gIconBox;
- EraseRect(&gIconBox);
- InsetRect(&rdraw, -1, -1);
- FrameRect(&rdraw);
- }
- /* draw the file information */
- if (gFileInDisplay && gFileUpToDate) {
- OSErr err;
- short baseLine;
- long textLength;
- char textbuf[256];
- FontInfo fin;
- Str255 name;
- /* begin drawing */
- TextFont(kFontIDGeneva); /* geneva */
- TextSize(9);
- GetFontInfo(&fin);
- /* draw the icon image */
- if (gHasIconServices)
- err = PlotIconRef(&gIconImage, kAlignNone, kTransformNone, kIconServicesNormalUsageFlag, gIconRef);
- else err = PlotIconSuite(&gIconImage, kAlignNone, kTransformNone, gIconSuite);
- /* draw the file name */
- baseLine = gIconImage.bottom + fin.ascent;
- memcpy(name, gTargetFile.name, gTargetFile.name[0] + 1);
- TruncString(gIconBox.right - gIconBox.left - 4, name, truncEnd);
- MoveTo((gIconBox.left + gIconBox.right - StringWidth(name))/2, baseLine);
- DrawString(name);
- /* draw the location */
- textLength = sprintf(textbuf, "vRefNum %d, parID %d", gTargetFile.vRefNum, gTargetFile.parID);
- baseLine += fin.ascent + fin.descent;
- MoveTo((gIconBox.left + gIconBox.right - TextWidth(textbuf, 0, textLength))/2, baseLine);
- DrawText(textbuf, 0, textLength);
- /* draw the type and flags */
- textLength = sprintf(textbuf, "%.4s %.4s 0x%.4X", &gType, &gCreator, gFlags);
- baseLine += fin.ascent + fin.descent;
- MoveTo((gIconBox.left + gIconBox.right - TextWidth(textbuf, 0, textLength))/2, baseLine);
- DrawText(textbuf, 0, textLength);
- /* end drawing */
- TextFont(systemFont); /* back to the system font */
- TextSize(12);
- } else {
- Rect rPic;
- rPic = (**gSplashPict).picFrame;
- OffsetRect(&rPic, -rPic.left, -rPic.top);
- OffsetRect(&rPic, (gIconBox.left + gIconBox.right - rPic.right)/2, (gIconBox.top + gIconBox.bottom - rPic.bottom)/2);
- DrawPicture(gSplashPict, &rPic);
- }
- /* gray the image if we're in the background */
- if ( ! (gForground && (theWindow == FrontWindow())) ) {
- GrayOutBox(&gIconBox);
- }
- /* restore previous colors */
- if (gColorExists) {
- RGBForeColor(&sForground);
- RGBBackColor(&sBackground);
- }
- }
-
-
-
- /* CreateFDPWindow creates the main finder drag pro window. It installs
- tracking handlers and sets up the controls and user items in the window. */
- static pascal OSErr CreateFDPWindow(DialogPtr *theDialog) {
- OSErr err;
- Boolean installedTracker, installedReceiver;
- short itemt;
- Rect itemb;
- Handle itemh;
- DialogPtr dialog;
-
- /* set up locals for recovery */
- dialog = NULL;
- installedTracker = installedReceiver = false;
-
- /* create the dialog */
- dialog = GetNewDialog(kFDPDialogResource, NULL, (WindowPtr) (-1));
- if (dialog == NULL) { err = memFullErr; goto bail; }
-
- /* grab and set up our dialog items */
- GetDialogItem(dialog, kFDPUserItem, &itemt, (Handle*) &itemh, &gIconBox);
- SetDialogItem(dialog, kFDPUserItem, userItem, (Handle) gFDPUserItemProc, &gIconBox);
- GetDialogItem(dialog, kFDPpromiseItem, &itemt, (Handle*) &gPromiseControl, &itemb);
- GetDialogItem(dialog, kFDPhfsItem, &itemt, (Handle*) &gRegularControl, &itemb);
-
- /* set initial control values */
- SetControlValue(gPromiseControl, (gDragMode == kUsePromiseHFS ? 1 : 0));
- SetControlValue(gRegularControl, (gDragMode == kUseRegularHFS ? 1 : 0));
-
- /* calculate the drawn icon's boundary */
- SetRect(&gIconImage, 0, 0, 32, 32);
- OffsetRect(&gIconImage, (gIconBox.right + gIconBox.left - 32) / 2, gIconBox.top + 16);
-
- /* install the drag handlers */
- err = InstallTrackingHandler(gMainTrackingHandler, dialog, NULL);
- if (err != noErr) { err = memFullErr; goto bail; }
- installedTracker = true;
- err = InstallReceiveHandler(gMainReceiveHandler, dialog, NULL);
- if (err != noErr) { err = memFullErr; goto bail; }
- installedReceiver = true;
-
- /* done, window complete */
- *theDialog = dialog;
- return noErr;
-
- bail:
- if (installedReceiver)
- RemoveReceiveHandler(gMainReceiveHandler, dialog);
- if (installedTracker)
- RemoveTrackingHandler(gMainTrackingHandler, dialog);
- if (dialog != NULL) DisposeDialog(dialog);
- return err;
- }
-
- /* DisposeFDPWindow disposes of any structures allocated for the
- main finder drag pro window. the call to SetNewDisplay with a
- NULL parameter forces it to deallocate any icons and the
- alias allocated for the item being displayed. */
- static void DisposeFDPWindow(DialogPtr theDialog) {
- SetNewDisplay(NULL);
- RemoveTrackingHandler(gMainTrackingHandler, theDialog);
- RemoveReceiveHandler(gMainReceiveHandler, theDialog);
- DisposeDialog(theDialog);
- }
-
-
-
-
- /* HitFDPWindow is called when the dialog manager's DialogSelect indicates
- that an item in the main finder drag pro window has been hit. Here,
- either we begin a drag, or we adjust the promise/regular hfs controls */
- static void HitFDPWindow(DialogPtr theDialog, EventRecord *event, short itemNo) {
- switch (itemNo) {
- case kFDPUserItem:
- if (gFileInDisplay) {
- Point where;
- Boolean isInSuite;
- OSErr err, err2;
- /* set up */
- SetPort(theDialog);
- where = event->where;
- GlobalToLocal(&where);
- /* if the click is in the icon.... */
- if (gHasIconServices)
- isInSuite = PtInIconRef(&where, &gIconImage, kAlignNone, kIconServicesNormalUsageFlag, gIconRef);
- else isInSuite = PtInIconSuite(where, &gIconImage, kAlignNone, gIconSuite);
- if (isInSuite) {
- /* draw the icon as 'selected' */
- if (gHasIconServices)
- err = PlotIconRef(&gIconImage, kAlignNone, kTransformSelected, kIconServicesNormalUsageFlag, gIconRef);
- else err = PlotIconSuite(&gIconImage, kAlignNone, kTransformSelected, gIconSuite);
- if (err == noErr) {
- /* is it a drag command? */
- if (WaitMouseMoved (event->where)) {
- /* if it is, drag it */
- err = DragOut(event);
- }
- /* restore the icon's original view */
- if (gHasIconServices)
- err2 = PlotIconRef(&gIconImage, kAlignNone, kTransformNone, kIconServicesNormalUsageFlag, gIconRef);
- else err2 = PlotIconSuite(&gIconImage, kAlignNone, kTransformNone, gIconSuite);
- if (err == noErr) err = err2;
- }
- if (err != noErr) {
- Str255 errStr;
- NumToString(err, errStr);
- ParamAlert(kDragFailedAlert, errStr, NULL);
- }
- }
- }
- break;
-
- case kFDPhfsItem: /* use regular hfs drags */
- gDragMode = kUseRegularHFS;
- SetControlValue(gPromiseControl, 0);
- SetControlValue(gRegularControl, 1);
- break;
-
- case kFDPpromiseItem: /* use promised hfs drags */
- gDragMode = kUsePromiseHFS;
- SetControlValue(gPromiseControl, 1);
- SetControlValue(gRegularControl, 0);
- break;
- }
- }
-
-
-
-
- /* MENU HANDLING ------------------------------------------------ */
-
-
-
- /* ResetMenus is called to reset the menus immediately before
- either MenuSelect or MenuKey is called. Here, we disable the
- quit command during file copies. */
- static void ResetMenus(void) {
- MenuHandle fileMenu;
- /* get the file menu from the current menu list */
- fileMenu = GetMenuHandle(mFile);
- /* disable quit if we're in the middle of copying a file */
- if (CopyFileInProgress())
- DisableItem(fileMenu, iQuit);
- else EnableItem(fileMenu, iQuit);
- }
-
-
- /* DoMenuCommand is called after either MenuSelect of MenuKey. The
- parameter rawMenuSelectResult is the result from one of these two routines.
- DoMenuCommand parses this result into its two parts, and dispatches
- the menu command as appropriate. */
- static void DoMenuCommand(long rawMenuSelectResult) {
- short menu, item;
- /* decode the MenuSelect result */
- menu = (rawMenuSelectResult >> 16);
- if (menu == 0) return;
- item = (rawMenuSelectResult & 0x0000FFFF);
- /* dispatch on result */
- switch (menu) {
- case mApple:
- if (item == iAbout) {
- /* show the about box. */
- ParamAlert(kAboutBoxAlert, NULL, NULL);
- } else if (item >= iFirstAppleItem) {
- Str255 deskAccName;
- /* open an apple menu item. */
- GetMenuItemText(GetMenuHandle(mApple), item, deskAccName);
- OpenDeskAcc(deskAccName);
- }
- break;
- case mFile:
- if (item == iQuit) gRunning = false; /* file.quit == quit */
- break;
- case mEdit:
- if (item == iClear) SetNewDisplay(NULL); /* edit.clear == clear the display */
- break;
- }
- /* unhilite the menu once we're done the command */
- HiliteMenu(0);
- }
-
-
-
- /* APPLE EVENT HANDLERS ------------------------------------------------ */
-
-
- /* BogusFinderEventHandler is an event handler installed for compatibility reasons
- as described below. Not all finders behave in this way, but or universal compatibility,
- applications wishing to drag and drop hfs flavors to the finder should add one of
- these handlers to their code. In cases where the finder does have this problem,
- this routine will lie dormant and will not be used.
-
- When a HFSFlavor item is provided to the Finder and the drop location is on a
- different volume, the finder will attempt to copy the file to the new volume. As
- a part of the copy operation, the finder sends some apple events to the frontmost
- application (assuming it's the finder) that are used to run the finder's copy progress
- windows. If our application happens to be frontmost, those events will be sent to
- us which will cause the Finder to cancel. By installing the handler, we avoid this problem
- by ignoring the bogus events ourselves.,.... */
- static pascal OSErr BogusFinderEventHandler(const AppleEvent *theEvent, AppleEvent *theReply, long refcon) {
- return noErr;
- }
-
-
-
- static OSErr GotReqParam(const AppleEvent *apple_event) {
- DescType retType;
- Size actSize;
- OSErr err;
- err = AEGetAttributePtr(apple_event, keyMissedKeywordAttr, typeWildCard, &retType, NULL, 0, &actSize);
- if (err == errAEDescNotFound)
- return noErr;
- else if (err == noErr)
- return errAEEventNotHandled;
- else return err;
- }
-
- /* OpenApplication is an apple event handler called for 'open application' apple events. */
- static pascal OSErr OpenApplication(const AppleEvent *appleEvt, AppleEvent* reply, long refcon) {
- OSErr err;
- if ((err = GotReqParam(appleEvt)) != noErr) return err;
- err = CreateFDPWindow(&gDialog);
- if (err != noErr) {
- Str255 errStr;
- NumToString(err, errStr);
- ParamAlert(kOpenAppFailedAlert, errStr, NULL);
- }
- return noErr;
- }
-
- /* CloseApplication is an apple event handler called for 'close application' apple events. */
- static pascal OSErr CloseApplication(const AppleEvent *appleEvt, AppleEvent* reply, long refcon) {
- OSErr err;
- if ((err = GotReqParam(appleEvt)) != noErr) return err;
- gRunning = false;
- return noErr;
- }
-
-
-
- /* EVENT HANDLING ------------------------------------------------ */
-
-
- /* HandleNextEvent handles the event in the event record *ev dispatching
- the event to appropriate routines. */
- static void HandleNextEvent(EventRecord *ev) {
- DialogPtr theDialog;
- WindowPtr theWindow;
- short itemNo;
-
- /* dialog pre-processing */
- if (((ev->what == keyDown) || (ev->what == autoKey)) && ((ev->modifiers & cmdKey) != 0)) {
- ResetMenus();
- DoMenuCommand(MenuKey((char) (ev->message & charCodeMask)));
- } else if (ev->what == osEvt) {
- if ( (((ev->message >> 24) & 0x0FF) == suspendResumeMessage) && ((ev->message & resumeFlag) != 0)) {
- /* switching in */
- ValidateFDPWindowDisplay();
- gForground = true;
- } else gForground = false;
- if (gDialog != NULL) {
- HiliteControl(gPromiseControl, (gForground ? 0 : 255));
- HiliteControl(gRegularControl, (gForground ? 0 : 255));
- DrawDialog(gDialog);
- }
- } else if (ev->what == updateEvt) {
- if (gDialog == ((DialogPtr) ev->message))
- ValidateFDPWindowDisplay();
- } else if (ev->what == activateEvt) {
- if (gDialog == ((DialogPtr) ev->message)) {
- HiliteControl(gPromiseControl, ((gDialog == FrontWindow()) ? 0 : 255));
- HiliteControl(gRegularControl, ((gDialog == FrontWindow()) ? 0 : 255));
- DrawDialog(gDialog);
- }
- }
-
- /* handle clicks in the dialog window */
- if (IsDialogEvent(ev))
- if (DialogSelect(ev, &theDialog, &itemNo)) {
- if (theDialog == gDialog)
- HitFDPWindow(theDialog, ev, itemNo);
- else if (theDialog == gCopyProgressWindow)
- HitCopyAsWindow(theDialog, ev, itemNo);
- }
-
- /* clicks and apple events... */
- if (ev->what == kHighLevelEvent && gAppleEvents) {
- AEProcessAppleEvent(ev);
- } else if (ev->what == nullEvent) {
- ValidateFDPWindowDisplay(); /* revalidate once every two seconds */
- } else if (ev->what == mouseDown)
- switch (FindWindow(ev->where, &theWindow)) {
-
- /* menu bar clicks */
- case inMenuBar:
- ResetMenus();
- DoMenuCommand(MenuSelect(ev->where));
- break;
-
- /* clicks in the close box, close the app */
- case inGoAway:
- if (TrackGoAway(theWindow, ev->where)) {
- gRunning = false;
- }
- break;
-
- /* allow window drags */
- case inDrag:
- if (theWindow == FrontWindow()) {
- Rect boundsRect = { -32000, -32000, 32000, 32000};
- DragWindow(theWindow, ev->where, &boundsRect);
- }
- break;
-
- /* desktop clicks, etc... */
- case inSysWindow:
- SystemClick(ev, theWindow);
- break;
- }
- }
-
-
- /* ProcessNextEvent calls WaitNextEvent to get the next event and then it passes
- the event along to the HandleNextEvent routine. sleepTime is passed to the
- WaitNextEvent routine in the sleep parameter. */
- void ProcessNextEvent(long sleepTime) {
- EventRecord ev;
- /* get the next event */
- if ( ! WaitNextEvent(everyEvent, &ev, sleepTime, NULL) )
- ev.what = nullEvent;
- HandleNextEvent(&ev);
- }
-
- /* FDPIdleProcedure is the idle procedure called by AEInteractWithUser while we are waiting
- for the application to be pulled into the forground. It simply passes the event along
- to HandleNextEvent */
- static pascal Boolean FDPIdleProcedure(EventRecord *theEvent, long *sleepTime, RgnHandle *mouseRgn) {
- HandleNextEvent(theEvent);
- return false;
- }
-
-
- /* ParamAlert is a general alert handling routine. If Apple events exist, then it
- calls AEInteractWithUser to ensure the application is in the forground, and then
- it displays an alert after passing the s1 and s2 parameters to ParamText. */
- short ParamAlert(short alertID, StringPtr s1, StringPtr s2) {
- if (gAppleEvents)
- AEInteractWithUser(kNoTimeOut, NULL, gAEIdleProc);
- ParamText(s1, s2, NULL, NULL);
- return Alert(alertID, NULL);
- }
-
-
-
-
- /* MAIN ------------------------------------------------ */
-
-
- int main(void) {
- OSErr err;
- long response;
-
-
- /* ***** set up the os ***** */
- /* set up our app */
- SetApplLimit(GetApplLimit());
- MaxApplZone();
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- TEInit();
- InitMenus();
- InitDialogs(0);
- FlushEvents(everyEvent, 0);
- InitCursor();
-
-
- /* ***** look at machine features ***** */
- /* apple events??? */
- if (Gestalt(gestaltAppleEventsAttr, &response) != noErr) response = 0;
- gAppleEvents = ((response & (1<<gestaltAppleEventsPresent)) != 0);
- /* check for the drag manager & translucent feature??? */
- if (Gestalt(gestaltDragMgrAttr, &response) != noErr) response = 0;
- gHasDragManager = ((response & (1 << gestaltDragMgrPresent)) != 0);
- gCanTranslucentDrag = ((response & (1 << gestaltDragMgrHasImageSupport)) != 0);
- /* icon services??? */
- if (Gestalt(gestaltIconUtilitiesAttr, &response) != noErr) response = 0;
- gHasIconServices = ((response & (1 << gestaltIconUtilitiesHasIconServices)) != 0);
- /* colour quickdraw */
- if (Gestalt(gestaltQuickdrawVersion, &response) != noErr) response = 0;
- gColorExists = (response >= gestalt8BitQD);
- /* colour quickdraw */
- if (Gestalt(gestaltThreadMgrAttr, &response) != noErr) response = 0;
- gHasThreads = ((response & (1<<gestaltThreadMgrPresent)) != 0);
- /* appearance */
- if (Gestalt(gestaltAppearanceAttr, &response) != noErr) response = 0;
- if ((response & (1<<gestaltAppearanceExists)) != 0) {
- err = RegisterAppearanceClient();
- if (err != noErr) goto bail;
- gAppearance = true;
- }
-
-
- /* ***** abort if features we need aren't present ***** */
- if ( ! gHasDragManager) { err = kNoDragMgrError; goto bail; }
- if ( ! gHasThreads) { err = kNoThreadMgrError; goto bail; }
-
-
- /* ***** install apple event handlers ***** */
- /* install our Apple event handlers */
- if (gAppleEvents) {
- AEEventHandlerUPP aehandler;
- /* the bogus finder event handler */
- aehandler = NewAEEventHandlerProc(BogusFinderEventHandler);
- if (aehandler == NULL) { err = memFullErr; goto bail; }
- err = AEInstallEventHandler ('cwin','****', aehandler, 0, false);
- if (err != noErr) goto bail;
- /* standard apple events */
- aehandler = NewAEEventHandlerProc(OpenApplication);
- if (aehandler == NULL) { err = memFullErr; goto bail; }
- err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, aehandler, 0, false);
- if (err != noErr) goto bail;
- aehandler = NewAEEventHandlerProc(CloseApplication);
- if (aehandler == NULL) { err = memFullErr; goto bail; }
- err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, aehandler, 0, false);
- if (err != noErr) goto bail;
- }
-
-
- /* ***** initialize the application's globals ***** */
- /* set up our routine descriptors */
- gFDPUserItemProc = NewUserItemProc(MyFDPUserItem);
- if (gFDPUserItemProc == NULL) { err = memFullErr; goto bail; }
- gMainTrackingHandler = NewDragTrackingHandlerProc(MyDragTrackingHandler);
- if (gMainTrackingHandler == NULL) { err = memFullErr; goto bail; }
- gMainReceiveHandler = NewDragReceiveHandlerProc(MyDragReceiveHandler);
- if (gMainReceiveHandler == NULL) { err = memFullErr; goto bail; }
- gSendDataProc = NewDragSendDataProc(MyDragSendDataProc);
- if (gSendDataProc == NULL) { err = memFullErr; goto bail; }
- gAEIdleProc = NewAEIdleProc(FDPIdleProcedure);
- if (gAEIdleProc == NULL) { err = memFullErr; goto bail; }
-
- /* get other resources */
- gSplashPict = GetPicture(kFDPSpashPictResource);
- if (gSplashPict == NULL) { err = resNotFound; goto bail; }
-
-
- /* ***** set up the menu bar ***** */
- SetMenuBar(GetNewMBar(kFDPMenuBarResource));
- DrawMenuBar();
- AppendResMenu(GetMenuHandle(mApple), 'DRVR');
-
- /* ***** run the app ***** */
- while (gRunning) {
- ProcessNextEvent(CopyFileInProgress() ? kCopySleepTime : kNormalSleepTime);
- YieldToAnyThread();
- }
-
- /* ***** tear down ***** */
- bail:
- switch (err) {
- case userCanceledErr:
- case noErr:
- /* no alert here */
- break;
- case kNoDragMgrError:
- ParamAlert(kNoDragManagerAlert, NULL, NULL);
- break;
- default:
- { Str255 errStr;
- NumToString(err, errStr);
- ParamAlert(kMainFailedAlert, errStr, NULL);
- }
- break;
- }
- if (gDialog != NULL) DisposeFDPWindow(gDialog);
- if (gAppearance)
- UnregisterAppearanceClient();
- ExitToShell();
- return 0;
- }
-
-
-